package com.talkyun.utils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class Looper extends Thread {
    private static ThreadGroup group = new ThreadGroup("openx-lp");
    private static Map<String, AtomicInteger> name2No = new ConcurrentHashMap<String, AtomicInteger>();

    private static String getThreadName(String name) {
        AtomicInteger no = name2No.get(name);
        if (no == null) {
            no = new AtomicInteger();
            name2No.put(name, no);
        }

        return name + "-" + no.incrementAndGet();
    }

    private AtomicInteger no = new AtomicInteger();

    private Looper self = this;
    private boolean run = false;
    private int interval = 10;
    private int errorPauseTime = 1000;

    private Looper(String name) {
        this(name, 10);
    }

    protected Looper(String name, int interval) {
        this(name, interval, interval * 3);
    }

    protected Looper(String name, int interval, int errorInterval) {
        super(group, getThreadName(name));

        super.setName(name + "-" + no.incrementAndGet());
        super.setDaemon(true);

        this.interval = interval;
        this.errorPauseTime = errorInterval;
    }

    @Override
    public void run() {
        run = true;
        while (run) {
            try {
                self.loop();
            } catch (Throwable t) {
                try {
                    loopThrowable(t);
                } catch (Throwable t2) {
                    // ignore
                }
                self.doSleep(errorPauseTime);
            }

            if (interval > 0) {
                self.loopSleep();
            }
        }
    }

    public void shutdown() {
        run = false;
    }

    protected void doSleep(int ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            // ignore
        }
    }

    protected void loopThrowable(Throwable t) {
        // ignore, sub-class may override
    }

    protected void loopSleep() {
        self.doSleep(interval);
    }

    protected abstract void loop() throws Throwable;
}